#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -- $0 "$@"
|#

;;;; Example MCP Server
;;;;
;;;; This file demonstrates how to create a basic MCP server
;;;; with two simple tools: echo and add
;;;;
;;;; Usage:
;;;;   ./example-mcp.ros
;;;;   ros example-mcp.ros
;;;;
;;;; With SLYNK support for remote debugging:
;;;;   SLYNK_PORT=4005 ./example-mcp.ros

(declaim (optimize (debug 3) (safety 3)))

;; Load required systems
(push "~/projects/lisp/clack-sse/" asdf:*central-registry*)
(push "~/projects/lisp/40ants-logging/" asdf:*central-registry*)
(push "~/projects/lisp/40ants-openrpc/" asdf:*central-registry*)
(push "~/projects/lisp/openrpc/" asdf:*central-registry*)

(declaim (optimize (debug 3) (safety 3)))

(ql:quickload '(:40ants-mcp :alexandria :local-time :40ants-slynk :defmain) :silent t)

(defpackage #:example-mcp-server
  (:use #:cl)
  (:import-from #:40ants-mcp)
  (:import-from #:40ants-logging)
  (:import-from #:serapeum
                #:fmt)
  (:import-from #:openrpc-server)
  (:import-from #:jsonrpc/errors)
  (:import-from #:log :info)
  (:import-from #:40ants-slynk
                #:start-slynk-if-needed)
  (:import-from #:alexandria)
  (:import-from #:40ants-mcp/content/text
                #:text-content)
  (:import-from #:defmain
                #:defmain)
  (:import-from #:40ants-mcp/tools
                #:define-tool)
  (:export #:main))
(in-package #:example-mcp-server)


(openrpc-server:define-api (example-tools :title "Example tools"))


(define-tool (example-tools echo) (text)
  (:summary "Simply returns the input text back to the caller.")
  (:param text string "Text to echo back.")
  (:result (soft-list-of text-content))
  
  (list (make-instance 'text-content
                       :text text)))


(define-tool (example-tools add) (a b)
  (:summary "Adds two numbers and returns the result.")
  (:param a integer "First number to add.")
  (:param b integer "Second number to add.")
  (:result (soft-list-of text-content))
  
  (list (make-instance 'text-content
                       :text (format nil "The sum of ~A and ~A is: ~A"
                                     a b (+ a b)))))


(defmain (main) ((port "TCP port to listen on. If given, Streaming HTTP transport will be used.")
                 (debug "If this flag set, then a debugger will be opened when you've conntected to the server with SLY."
                        :flag t))
  "Main entry point for the Roswell script"
  
  (40ants-logging:setup-for-backend
   :filename (make-pathname :directory '(:absolute "tmp")
                            :name "example-mcp"
                            :type "log")
   :level :debug)

  ;; Start SLYNK server if SLYNK_PORT environment variable is set
  (start-slynk-if-needed)

  (when debug
    (setf jsonrpc/errors:*debug-on-error* t))

  (40ants-mcp/server/definition:start-server example-tools
                                             :transport (cond
                                                          (port
                                                           :http)
                                                          (t
                                                           :stdio))
                                             :port (parse-integer port)))
